import java.math.BigDecimal;
import java.math.RoundingMode;

public class Run {

	public static IFunction f1ab = new IFunction() {

		@Override
		public double compute(double x) {
			return Math.log(1 + x + x * x);
		}
	};

	public static IFunction f1c = new IFunction() {

		@Override
		public double compute(double x) {
			if (x == 0)
				return 1;
			return Math.tan(x) / x;
		}
	};
	
	private static double[] q23a = { 19, -27, 42, 27, 13, 1 };

	public static IFunction f3a = new IFunction() {

		@Override
		public double compute(double x) {
			return Algs.horner(q23a, x);
		}
	};
	
	
	public static IFunction f3b = new IFunction() {

		@Override
		public double compute(double x) {
			return Math.pow(x, 2 ) - Math.sin(5*x);
		}
	};
	
	public static IFunction f3bDerivative	 = new IFunction() {

		@Override
		public double compute(double x) {
			return x*2 - 5* Math.cos(5*x);
		} 
	};
	

	public static IFunction f3c = new IFunction() {

		@Override
		public double compute(double x) {
			return Math.cos(x)*Math.cosh(x) + 1;
		}
	};
	
	public static IFunction f3cDerivative	 = new IFunction() {

		@Override
		public double compute(double x) {
			return Math.cos(x)*Math.sinh(x) - Math.sin(x)*Math.cosh(x);
		}
	};
	
	
	/// aitkens ?!
	public static ISeries s2a = new ISeries() {
		
		//private double last = -1;
		@Override
		public double get(int n) {
			if (n==0)
				return 0;
			return Math.sqrt(1+this.get(n-1));
		}
		
		/*
		@Override
		public double next() {
			if (this.last < 0)
			{
				this.last = 0;
			}
			else 
			{
				this.last = Math.sqrt(1+this.last);
			}
			return this.last;
		}
		*/
	};
	
	
	// richardson ?!
	public static ISeries s2b = new ISeries() {
		
		private double last = -1;
		@Override
		public double get(int n) {
			BigDecimal res = BigDecimal.ONE;
			for (int k = 1; k <= n; k++) {
				res =  res.multiply(BigDecimal.ONE.divide(bd(16*Math.pow(k, 2)),20,BigDecimal.ROUND_HALF_UP).negate().add(BigDecimal.ONE));
			}
			return res.doubleValue();
		}
	
	};
	
	

	private static BigDecimal bd(double d) {
		return new BigDecimal(Double.toString(d));
	}
	

	public static void test(Double... coefs)
	{
		for (int i = 0; i < coefs.length; i++) {
			System.out.println(coefs[i]);
		}
	}

	public static void q1a() {
		// for m = 19 i =2.92562389906984E-13
		int maxpanels = 20;
		int a = 0;
		int b = 1;
		String res = "0.554818115119273462389906984";
		BigDecimal result = new BigDecimal(res);

		for (int m = 1; m < maxpanels; m++) {
			BigDecimal i = Algs.numericIntegration(m, f1ab, bd(a), bd(b));
			// System.out.println(i);
			System.out.println(m+","+i+","+i.subtract(result).abs());
		}
		
	}
	
	public static void q1b() {
		BigDecimal tol = new BigDecimal("2.92108715768331767361455176908694703528682E-13");
		int a = 0;
		int b = 1;
		BigDecimal[] result = Algs.AddaptiveNumericIntegration(tol, f1ab, bd(a), bd(b));
		for (int i = 0; i < result.length; i++) {			
			System.out.println(result[i]);
		}
	}
	
	
	
	public static void q1c ()
	{
		String resstr = "0.8489671307248948004094370470819948047505849315451416131"; // from wolfram alpha
		int e = 0;
		int p = 10;
		double a = 0;
		double b = Math.PI/4;
		double tol = 0.5*Math.pow(10, e-p+1);
		BigDecimal[] res = Algs.AddaptiveNumericIntegration(bd(tol), f1c, bd(a), bd(b));
		for (int i = 0; i < res.length; i++) {			
			System.out.println(res[i]);
		}
		
	
	}
	
	public static void q2a()
	{
		// concverges to ~ 1.6
		int e = 0;
		int p = 6;
		double tol = 0.5*Math.pow(10, e-p+1);
		
		int n = 100;
		BigDecimal[] series = new BigDecimal[n];
		for (int i = 0; i < series.length; i++) {
			series[i] = bd(s2a.get(i+1));
		}
		
		BigDecimal[] res = Algs.aitken(series, bd(tol), n-2);
		for (int i = 0; i < res.length-1; i++) {
			//System.out.println(series[i]+","+res[i]);
			//System.out.println(series[i]);
		}
	}
	
	public static void q2b()
	{
		// concverges to ~ 0.9
		int e = -1;
		int p = 4;
		double tol = 0.5*Math.pow(10, e-p+1);
		int s = 2;
		int n = 200;
		BigDecimal[] series = new BigDecimal[n];
		for (int i = 0; i < series.length; i++) {
			series[i] = bd(s2b.get(i+1));
		}
		//System.out.println(tol);
		
		BigDecimal[] res = Algs.richardson(series, bd(tol), n-2,s);
		BigDecimal expected = series[series.length-1];
//		for (int i = 0; i < res.length-1; i++) {
//			System.out.println(i+")"+res[i]+" : "+ res[i].subtract(expected).abs());
//			System.out.println(series[i]);
//		}	
	}
	
	

	// ****************************************************************** q 3 a ******************************************************************
	// http://www.wolframalpha.com/input/?i=pow%28x%2C5%29+%2B+13pow%28x%2C4%29+%2B+27pow%28x%2C3%29+%2B42pow%28x%2C2%29+-27x%2B9
	// x = -10.897543627590948470



	public static void q3a() {

		
		BigDecimal tol = new BigDecimal("10e-8").multiply(bd(0.5));
		System.out.println("the tolerance is " + tol.doubleValue());
		double [] res = Algs.biSection(tol.doubleValue(), f3a, -15,-5);
		System.out.println("the error is " + res[0] + " the approximation is" + res[1] );
		
	}


	//****************************************************************** q 3 b ******************************************************************
	// f' = x*2 - 5*cos(5x) f'' = 2 + 25sin(5x) 
	//' http://www.wolframalpha.com/input/?i=pow%28x%2C2%29+-+sin%285x%29
	// x= 0.5636520971663619290

	
	
	public static void q3b(){
	    BigDecimal tol = new BigDecimal("10e-10").multiply(bd(0.5));
	    System.out.println("the tolerance is " + tol);
		double x0 = 0.001;
		double h = 0.1;
		System.out.println("The root is " + Algs.newtonRaphson(f3b, f3bDerivative , x0 , h , tol.doubleValue()));
		
	}
	

	

	//****************************************************************** q 3 c ******************************************************************
	// f' = x*2 - 5*cos(5x) f'' = 2 + 25sin(5x) 
	//f http://www.wolframalpha.com/input/?i=cos%28x%29*cosh%28x%29+%2B+1
	// x = -1.87510406871196
		

	
	public static void q3c(){
	    BigDecimal tol = new BigDecimal("10e-8").multiply(bd(0.5));
	    System.out.println("the tolerance is " + tol);
		double x0 = -4; 
		double h = 0.1;
		double res = -1;
	
		x0 = Algs.secant(f3c, f3cDerivative , x0 , h , tol.doubleValue());

		System.out.println("The root is " + x0);
		
	}
	

	public static void main(String[] args)
	{	
		//q1a();
		//q1b();
		//q1c();
		//q2a();
		//q2b();
		//q3a();
		//q3b();
		//q3c();
		
		
		
		
		/**
		double x=    -10.89838394895196 - 0.0000000005;
		double dif = 0.0000000001;
		for (int i=0; i<5 ; i++){
			x=x + dif;
			System.out.println(x );
			//System.out.println(f3a.compute(x));
		}
		 
	
		for (int i=0; i<5 ; i++){
			x=x+dif;
			System.out.println(x );
			//System.out.println(f3a.compute(x));
		}
		*/

	}

	


}
